package com.mp.approvalreq.dao.impl;

import com.mp.approvalreq.dao.ExpenseDao;
import com.mp.approvalreq.entity.Expense;
import com.plusmoney.util.SQLLogger;
import com.plusmoney.util.Utils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ExpenseDaoImpl extends AbstractDao implements ExpenseDao {

    private static final Logger logger = LoggerFactory.getLogger(ExpenseDaoImpl.class);

    private Connection connection;

    public ExpenseDaoImpl(Connection connection) {
        this.connection = connection;
    }

    private PreparedStatement getPreparedStatement(String sql) throws SQLException {
        return connection.prepareStatement(sql);
    }

    @Override
    String getQuerySql(String condition) {
        final String query = "select id, company_id, company_info_id, request_id, total_amount,"
                + " expense_item, pay_amount, pay_date, attach_file, remark,"
                + " type"
                + " from sys_approval_expense";
        return String.format("%s %s", query, condition);
    }

    @Override
    Expense getObject(ResultSet rs) throws SQLException {
        Expense expense = new Expense();
        expense.setId(rs.getInt(1));
        expense.setCompanyId(rs.getInt(2));
        expense.setCompanyInfoId(rs.getInt(3));
        expense.setRequestId(rs.getInt(4));
        expense.setTotalAmount(rs.getBigDecimal(5));

        expense.setExpenseItem(rs.getString(6));
        expense.setPayAmount(rs.getBigDecimal(7));
        expense.setPayDate(rs.getString(8));
        expense.setAttachFile(rs.getString(9));
        expense.setRemark(rs.getString(10));

        expense.setType(rs.getInt(11));
        return expense;
    }


    @Override
    public void insertBatchExpenses(List<Expense> expenses) throws SQLException {
        String sql = "insert into sys_approval_expense set"
                + " company_id = ?, company_info_id = ?, request_id = ?, total_amount = ?, expense_item = ?,"
                + " pay_amount = ?, pay_date = ?, attach_file = ?, remark = ?, type = ?,"
                + " approval_num = ?, create_time = now()";

        try (PreparedStatement ps = getPreparedStatement(sql)) {
            for (Expense expense : expenses) {
                ps.setInt(1, expense.getCompanyId());
                ps.setInt(2, expense.getCompanyInfoId());
                ps.setInt(3, expense.getRequestId());
                BigDecimal totalAmount = expense.getTotalAmount();
                if (Utils.isNotNull(totalAmount)) {
                    totalAmount = totalAmount.stripTrailingZeros();
                }
                ps.setBigDecimal(4, totalAmount);
                ps.setString(5, expense.getExpenseItem());

                BigDecimal payAmount = expense.getPayAmount();
                if (Utils.isNotNull(payAmount)) {
                    payAmount = payAmount.stripTrailingZeros();
                }
                ps.setBigDecimal(6, payAmount);
                ps.setString(7, expense.getPayDate());
                ps.setString(8, expense.getAttachFileStr());
                ps.setString(9, expense.getRemark());
                ps.setInt(10, expense.getType());

                ps.setString(11, expense.getApprovalNum());
                logger.info(SQLLogger.logSQL(sql, expense.getCompanyId(), expense.getCompanyInfoId(), expense.getRequestId(),
                        totalAmount, expense.getExpenseItem(), payAmount, expense.getPayDate(), expense.getAttachFileStr(),
                        expense.getRemark(), expense.getType(), expense.getApprovalNum()));

                ps.addBatch();
            }
            ps.executeBatch();
        }
    }

    @Override
    public void deleteExpensesByRequestId(Integer requestId, Integer companyId) throws SQLException {
        String sql = "update sys_approval_expense set state = 2, update_time = now() where request_id = ? and company_id = ?";

        try (PreparedStatement ps = getPreparedStatement(sql)) {
            ps.setInt(1, requestId);
            ps.setInt(2, companyId);
            logger.info(SQLLogger.logSQL(sql, requestId, companyId));

            ps.executeUpdate();
        }
    }

    @Override
    public List<Expense> selectExpensesByRequestId(Integer requestId) throws SQLException {
        List<Expense> list = new ArrayList<>();
        String sql = getQuerySql("where request_id = ?");

        try (PreparedStatement ps = getPreparedStatement(sql)) {
            ps.setInt(1, requestId);
            logger.info(SQLLogger.logSQL(sql, requestId));

            try (ResultSet rs = ps.executeQuery()) {
                while (rs.next()) {
                    list.add(getObject(rs));
                }
            }
        }
        return list;
    }

    @Override
    public Map<Integer, List<Expense>> selectExpensesByRequestIds(String requestIds) throws SQLException {
        Map<Integer, List<Expense>> map = new HashMap<>();
        if (StringUtils.isEmpty(requestIds)) {
            return map;
        }
        String sql = getQuerySql("where request_id in(" + requestIds + ")");

        try (PreparedStatement ps = getPreparedStatement(sql)) {
            logger.info(sql);

            try (ResultSet rs = ps.executeQuery()) {
                while (rs.next()) {
                    Expense expense = getObject(rs);
                    if (!map.containsKey(expense.getRequestId())) {
                        map.put(expense.getRequestId(), new ArrayList<>());
                    }
                    map.get(expense.getRequestId()).add(expense);
                }
            }
        }
        return map;
    }
}
